home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 17 / CU Amiga Magazine's Super CD-ROM 17 (1997)(EMAP Images)(GB)[!][issue 1997-12].iso / CUCD / Programming / DiceSource / src / vcommon / vmenu.c < prev   
C/C++ Source or Header  |  1997-09-09  |  13KB  |  428 lines

  1. #include "project.h"
  2. #ifdef PROJECT_VOPTS
  3.    #include "vopts.h"
  4. #endif
  5. #ifdef PROJECT_VMAKE
  6.    #include "vmake.h"
  7. #endif
  8. #include <proto/gadtools.h>
  9.  
  10. Prototype void enable_menu(void);
  11. Prototype struct Menu *create_menus(struct NewMenu *menulist);
  12. Prototype int layout_menus(struct Menu *menus);
  13. Prototype void free_menus(struct Menu *menus);
  14. Prototype void ghost_menus(void);
  15. Prototype void unghost_menus(void);
  16.  
  17. /***********************************************************************************
  18.  * Procedure: enable_menu
  19.  * Synopsis:  enable_menu();
  20.  * Purpose:   Attach any system defined menus to the current window.
  21.  ***********************************************************************************/
  22. void enable_menu()
  23. {
  24.    int i, level, newlev, count[4];
  25.    struct NewMenu *newmenu;
  26.  
  27.    if (global.window == NULL) return;
  28.  
  29.    /* Let us go through and validate the menu they have constructed */
  30.    level = 0;
  31.    newmenu = global.menuitem;
  32.    for (i = 0; i < MAX_MENU; i++)
  33.    {
  34.       newlev = newmenu[i].nm_Type;
  35.       if (newlev > level)
  36.       {
  37.          level++;
  38.          /* Make sure we are going down only one level */
  39.          if (newmenu[i].nm_Type != level || level > MENU_SUB) return;
  40.          count[level] = 0; /* Initialize our count */
  41.       }
  42.       else if (newlev == level)
  43.       {
  44.          /* Make sure we don't have two TITLES in a row */
  45.          if (level == MENU_MENU) return;
  46.          count[level]++;
  47.       }
  48.       else
  49.       {
  50.          /* We are going up a level.  Validate the counts on the way up */
  51.          if (newlev < MENU_END) return;
  52.          while (level > newlev)
  53.          {
  54.             if (count[level] >= "!\x20\x40\x20"[level])
  55.                return;
  56.             else
  57.                level--;
  58.          }
  59.          /* When we hit the end of the menus, break */
  60.          if (level == 0) break;
  61.          count[level]++;
  62.       }
  63.  
  64.    }
  65.    /* Lastly ensure that they had an END marker */
  66.    if (level) return;
  67.  
  68.    if (!(global.menu = create_menus(newmenu)))
  69.       return;
  70.  
  71.    if (!layout_menus(global.menu))
  72.       return;
  73.  
  74.    SetMenuStrip(global.window, global.menu);
  75. }
  76.  
  77. /***********************************************************************************
  78.  * Procedure: create_menus
  79.  * Synopsis:  Menu = create_menus(NewMenu);
  80.  * Purpose:   Create the appropriate menu structures for a given NewMenu list
  81.  ***********************************************************************************/
  82. struct Menu *create_menus(struct NewMenu *menulist
  83.                          )
  84. {
  85.    int i;
  86.    struct Menu   *retmenu;
  87.    struct XMenu  *thismenu;
  88.    struct XItem  *thisitem;
  89.    static struct Image sep_image = {5, 1, 1000, 2,0, NULL, 0,0, NULL};
  90.  
  91.  
  92.    if (GadToolsBase != NULL)
  93.    {
  94.       struct TagItem taglist[2];
  95.  
  96.       taglist[0].ti_Tag = GTMN_FrontPen;
  97.       taglist[0].ti_Data = 0;
  98.       taglist[1].ti_Tag = TAG_DONE;
  99.  
  100.       return(CreateMenusA(menulist, taglist));
  101.    }
  102.  
  103.    /* We don't have GadTools around to do the work for us, so just create the */
  104.    /* Menu structures directly.                                               */
  105.  
  106.    retmenu = NULL;  /* Default to giving them NOTHING */
  107.  
  108.    for (i = 0; i < MAX_MENU; i++)
  109.    {
  110.       switch (menulist[i].nm_Type)
  111.       {
  112.          case NM_TITLE:
  113.             {
  114.                struct XMenu  *newmenu;
  115.  
  116.                newmenu = (struct XMenu *)get_mem(sizeof(struct XMenu));
  117.                if (newmenu == NULL)
  118.                {
  119.                   free_menus(retmenu);
  120.                   return(NULL);
  121.                }
  122.  
  123.                /* Link the menu structure onto the list of other menus */
  124.                if (retmenu == NULL)
  125.                   retmenu = &newmenu->menu;
  126.                else
  127.                   thismenu->menu.NextMenu = &newmenu->menu;
  128.  
  129.                thismenu = newmenu;
  130.             }
  131.  
  132.             thismenu->menu.Flags    = MENUENABLED;
  133.             thismenu->menu.MenuName = (BYTE *)menulist[i].nm_Label;
  134.             thismenu->userdata      = menulist[i].nm_UserData;
  135.             thismenu->image         = sep_image;
  136.             break;
  137.  
  138.         case NM_ITEM:
  139.             if (thismenu == NULL) return(NULL);
  140.  
  141.             {
  142.                struct XItem  *newitem;
  143.  
  144.                newitem = (struct XItem *)get_mem(sizeof(struct XItem));
  145.                if (newitem == NULL)
  146.                {
  147.                   free_menus(retmenu);
  148.                   return(NULL);
  149.                }
  150.                if (thismenu->menu.FirstItem == NULL)
  151.                   thismenu->menu.FirstItem = &newitem->item;
  152.                else
  153.                   thisitem->item.NextItem  = &newitem->item;
  154.                thisitem = newitem;
  155.             }
  156.  
  157.             if (menulist[i].nm_Label == NM_BARLABEL)
  158.             {
  159.                thisitem->item.Flags        = 0;
  160.                thisitem->item.ItemFill     = &thismenu->image;
  161.             }
  162.             else
  163.             {
  164.                /* fill in the intuitext with some reasonable defaults */
  165.  
  166.                thisitem->itext.FrontPen    = 0;
  167.                thisitem->itext.DrawMode    = JAM1;
  168.                thisitem->itext.LeftEdge    = 5;
  169.                thisitem->itext.TopEdge     = 1;
  170.                thisitem->itext.ITextFont   = &global.ri.TextAttr;
  171.                thisitem->itext.IText       = menulist[i].nm_Label;
  172.  
  173.                thisitem->item.Flags        = ITEMTEXT|ITEMENABLED|HIGHCOMP;
  174.                thisitem->item.ItemFill     = (APTR)&thisitem->itext;
  175.  
  176.                if (menulist[i].nm_CommKey)
  177.                {
  178.                   thisitem->item.Command   = *menulist[i].nm_CommKey;
  179.                   thisitem->item.Flags    |= COMMSEQ;
  180.                }
  181.             }
  182.             thisitem->userdata = menulist[i].nm_UserData;
  183.             break;
  184.  
  185.          case NM_END:
  186.              return(retmenu);
  187.       }
  188.    }
  189.    return(retmenu);
  190. }
  191.  
  192. /***********************************************************************************
  193.  * Procedure: layout_menus
  194.  * Synopsis:  rc = layout_menus(Menu);
  195.  * Purpose:   Lays out a menu given the current global information
  196.  ***********************************************************************************/
  197. int layout_menus(struct Menu *menus)
  198. {
  199.    struct XMenu     *menu;
  200.    struct XItem     *item;
  201.    int              xpos;
  202.  
  203.    if (GadToolsBase != NULL)
  204.    {
  205.       struct VisualInfo *vi;
  206.       struct TagItem taglist;
  207.       int rc;
  208.  
  209.       taglist.ti_Tag = TAG_DONE;
  210.  
  211.       rc = 0;
  212.       if ((vi = GetVisualInfoA(global.window->WScreen, &taglist)))
  213.       {
  214.          rc = LayoutMenusA(global.menu, vi, &taglist);
  215.          FreeVisualInfo(vi);
  216.       }
  217.       return(rc);
  218.    }
  219.  
  220.    xpos = VBAR;
  221.  
  222.    for (menu = (struct XMenu *)menus; menu;
  223.         menu = (struct XMenu *)menu->menu.NextMenu)
  224.    {
  225.       int width, ypos;
  226.  
  227.       /* set the x position of the menu to the next available position.
  228.        * Set the menu width based on the size of the text.
  229.        */
  230.  
  231.       menu->menu.LeftEdge = xpos;
  232.       menu->menu.Width    = text_width(menu->menu.MenuName) + DVBAR;
  233.  
  234.       /* set the initial item y-position to just below the title bar */
  235.  
  236.       ypos = 0;
  237.  
  238.       /* walk through the list of items for the first pass. The object
  239.        * is to find the width of the largest item. We will also set
  240.        * the y-position of each item on this pass.
  241.        */
  242.  
  243.       width = menu->menu.Width;    /* make items at least as big as menu */
  244.  
  245.       for (item = (struct XItem *)menu->menu.FirstItem;
  246.            item;
  247.            item = (struct XItem *)item->item.NextItem)
  248.       {
  249.          int  iwidth;
  250.  
  251.          /* set the y-position of the item to the next available. Also,
  252.           * put the item just to the left of the menu. You can make
  253.           * this number zero if you prefer.
  254.           */
  255.  
  256.          item->item.TopEdge = ypos;
  257.          item->item.LeftEdge = -VBAR;
  258.  
  259.          /* if it's a text item, see how big it is. */
  260.  
  261.          if (item->item.Flags & ITEMTEXT)
  262.          {
  263.             struct IntuiText *itext;
  264.  
  265.             itext = (struct IntuiText *)item->item.ItemFill;
  266.  
  267.             /* the height is just the font height + 2. The width is
  268.              * based on the string pixel width.
  269.              */
  270.  
  271.             item->item.Height = global.ri.FontSize + 2;
  272.             iwidth = text_width(itext->IText) + 10;
  273.  
  274.             /* if it has a command-key sequence, then add in the space needed
  275.              * for the command key and the command symbol. Note that in
  276.              * lo-res, we should actually use LOWCOMMWIDTH, but I'm
  277.              * feeling lazy today.
  278.              */
  279.  
  280.             if (item->item.Flags & COMMSEQ)
  281.             {
  282.                char buf[2];
  283.  
  284.                buf[0] = item->item.Command;
  285.                buf[1] = 0;
  286.                iwidth += text_width(buf) + COMMWIDTH + 8;
  287.             }
  288.          }
  289.          else
  290.          {
  291.             /* separator bars are always the same height */
  292.             item->item.Height = 4;
  293.             iwidth = 0; /* nasty things happen in Dos 1.3 if not initialized */
  294.          }
  295.  
  296.          /* update the y-position variable. Make sure the items don't
  297.           * run off the bottom.
  298.           */
  299.  
  300.          ypos  += item->item.Height;
  301.          if (ypos >= (global.ri.ScreenHeight - DHBAR))
  302.             return(0);
  303.  
  304.           /* now see if this item is the largest one. */
  305.           if (iwidth > width) width = iwidth;
  306.       }
  307.  
  308.       /* on our second pass, we set the widths of all the items to the
  309.        * width of the largest item so that it looks good. In addition,
  310.        * we are going to adjust menus that might run off the right edge.
  311.        */
  312.  
  313.       for (item = (struct XItem *)menu->menu.FirstItem;
  314.           item;
  315.           item = (struct XItem *)item->item.NextItem)
  316.       {
  317.          item->item.Width = width;
  318.          if ((xpos + width) >= (global.ri.ScreenWidth - 2))
  319.             item->item.LeftEdge =
  320.                    global.ri.ScreenWidth - 2 - xpos - width;
  321.       }
  322.  
  323.       menu->image.Width = width - 7;
  324.  
  325.       /* now update the x position variable, make sure that the menu
  326.        * header is not off the edge of the screen, and add a little space
  327.        * between the headers. Feel free to make this number whatever
  328.        * you want. If you are feeling really ambitious, you could
  329.        * make this number adaptable.
  330.        */
  331.       xpos += menu->menu.Width;
  332.       if (xpos > global.ri.ScreenWidth) return(NULL);
  333.       xpos += 8;
  334.    }
  335.    return(TRUE);
  336. }
  337.  
  338. /***********************************************************************************
  339.  * Procedure: free_menus
  340.  * Synopsis:  free_menus(Menu);
  341.  * Purpose:   Return any storage allocated for a given Menu structure.
  342.  ***********************************************************************************/
  343. void free_menus(struct Menu *menus)
  344. {
  345.    struct XMenu *menu, *nextmenu;
  346.    struct XItem *item, *nextitem;
  347.  
  348.    if (global.window)
  349.       ClearMenuStrip(global.window);
  350.  
  351.    if (!menus) return;
  352.  
  353.    if (GadToolsBase != NULL)
  354.    {
  355.       FreeMenus(menus);
  356.    }
  357.  
  358.    else
  359.    {
  360.       for (menu = (struct XMenu *)menus; menu; menu = nextmenu)
  361.       {
  362.          nextmenu = (struct XMenu *)menu->menu.NextMenu;
  363.          for (item = (struct XItem *)menu->menu.FirstItem;
  364.               item;
  365.               item = nextitem)
  366.          {
  367.             nextitem = (struct XItem *)item->item.NextItem;
  368.             free_mem(item, sizeof(struct XItem));
  369.          }
  370.          free_mem(menu, sizeof(struct XMenu));
  371.       }
  372.    }
  373.    global.menu = NULL;
  374. }
  375.  
  376.  
  377. /***********************************************************************************
  378.  * Procedure: ghost_menus
  379.  * Synopsis:  ghost_menus();
  380.  * Purpose:   disable all menu entries except Open and New  
  381.  ***********************************************************************************/
  382. void ghost_menus(void)
  383. {
  384.    int i;
  385.    char *udp;
  386.  
  387.    free_menus(global.menu);
  388.  
  389.    for (i = 0; i < MAX_MENU; i++)
  390.    {
  391.  
  392.       if (global.menuitem[i].nm_Type == NM_ITEM) /* only ghost entries */
  393.       {
  394.          /* to allow flexible menu configuration, base our checks on   */
  395.          /* what the menu entry is programmed to do.  We allow READ,   */
  396.          /* NEW or QUIT when no project is loaded, ghost anything else.*/
  397.          udp = global.menuitem[i].nm_UserData;
  398.          if (udp) /* Menu bars don't have user data */
  399.             if ((strnicmp(udp, "read", 4) != 0)
  400.                && (strnicmp(udp, "new",  3) != 0)
  401.                && (strnicmp(udp, "quit", 4) != 0))
  402.                global.menuitem[i].nm_Flags |= NM_ITEMDISABLED;
  403.       }
  404.    }
  405.  
  406.    enable_menu();
  407. }
  408.  
  409.  
  410. /***********************************************************************************
  411.  * Procedure: unghost_menus
  412.  * Synopsis:  unghost_menus();
  413.  * Purpose:   reenable all menu entries (undo effect of ghost_menus())  
  414.  ***********************************************************************************/
  415. void unghost_menus(void)
  416. {
  417.    int i;
  418.  
  419.    free_menus(global.menu);
  420.  
  421.    for (i = 0; i < MAX_MENU; i++)
  422.    {
  423.       global.menuitem[i].nm_Flags &= ~NM_ITEMDISABLED;
  424.    }
  425.  
  426.    enable_menu();
  427. }
  428.